﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Dynamic;
using zijian666.SuperConvert.Interface;

namespace zijian666.SuperConvert.Dynamic
{
    /// <summary>
    /// 基于 <seealso cref="NameValueCollection" /> 的动态类型
    /// </summary>
    internal class DynamicNameValueCollection : DynamicObjectBase<NameValueCollection>
    {
        public DynamicNameValueCollection(NameValueCollection value, IConvertSettings convertSettings)
            : base(value, convertSettings)
        {
            if (value is null)
            {
                throw new ArgumentNullException(nameof(value));
            }
        }

        public override IEnumerable<string> GetDynamicMemberNames() => Value.AllKeys;

        protected override object this[int index]
        {
            get => index < 0 || index >= Value.Count ? null : Value[index];
            set => Value[Value.GetKey(index)] = value.Convert<string>(ConvertSettings).Value;
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if ((Value.Count == 1) && TryChangeType(Value[0], binder.ReturnType, out result))
            {
                return true;
            }
            return TryChangeType(Value, binder.ReturnType, out result);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = Value[binder.Name];
            if (result != null)
            {
                if (TryChangeType(result, binder.ReturnType, out result))
                {
                    result = WrapToDynamic(result);
                    return true;
                }
            }

            result = DynamicPrimitive.Null;
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            if (IsReadOnly)
            {
                return false;
            }
            Value[binder.Name] = value.To<string>();
            return true;
        }

        private object Indexer(object[] indexes)
        {
            if ((indexes == null) || (indexes.Length != 1))
            {
                return null;
            }
            var index = indexes[0];
            if (index is string name)
            {
                return Value[name];
            }
            var i = index.To(-1);
            if ((i < 0) || (i >= Value.Count))
            {
                return null;
            }
            return Value[i];
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            result = Indexer(indexes);
            if (result != null)
            {
                if (TryChangeType(result, binder.ReturnType, out result))
                {
                    result = WrapToDynamic(result);
                    return true;
                }
            }

            result = DynamicPrimitive.Null;
            return true;
        }

        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
        {
            if (IsReadOnly)
            {
                return false;
            }

            if (indexes.Length != 1)
            {
                return false;
            }
            var index = indexes[0];
            var str = value.To<string>();
            if (index is string name)
            {
                Value[name] = str;
                return true;
            }
            var i = index.To(-1);
            if ((i < 0) || (i >= Value.Count))
            {
                return false;
            }
            Value[Value.GetKey(i)] = str;
            return true;
        }
    }
}
